#include <string>
#include <iostream>
#include <conio.h>
//#include "RoadMap.h"
#include "Utilities.h"
#include "FileUtilities.h"

#define ADD 1
#define REMOVE 0
#define ZERO_ASCII 0x30
#define MMENU_SIZE 9

using std::string;

RoadMap * MAP;
GraphViewer *gv;
int JUNG_ON = 2; //0: JUNG is off; 1: JUNG is on; 2: JUNG is off (first time)
vector<vector<RoadNode*>> circuits;
vector<vector<int>> circuitIDs;
extern vector<RoadNode*> potenciallyOptimal;

/**
 * Writes a textual menu on the screen.
 * @param message E.g. "Choose an option from below."
 * @param options List of menu options
 * @param n Length of options[]
 * @return Integer with a valid choice. 0 <= return <= n
 */
int putMenu(string message, string * options, int n){
	system("cls");
	cout << "\n  Colleccao e Analise de Lixo, SA\n";
	cout << "\n  " << message;
	int i;
	for(i=0; i<n; i++){
		std::cout << "\n   " << i+1 << "  - " << options[i];
	}
	cout << "\n   0 <- Sair\n\t";
	char s = 0;
	s = _getch();
	while(s < ZERO_ASCII || s > ZERO_ASCII + n){
		s = _getch();
		cout << "[" << s << "]\n";
	}
	return s - ZERO_ASCII;

	cout << endl;
}

void editCollectable(bool action){
	cout << "\nType the ID of the location where you wish to ";
	if(!action) cout << "set";
	else		cout << "remove";
	cout << " a collectable.\n";
	cout << "You can also type exit to return to the previous menu.\n";
	string idString = "";
	int id;
	RoadNode * roadNode = NULL;
	/**
	 * Using cin to get user input.
	 * http://www.cplusplus.com/forum/articles/6046/ 
	 */
	while (true) {
		cout << "Please enter a valid id: ";
		getline(cin, idString);
		if (!idString.compare("exit")){
			return;
		}

		// This code converts from string to number safely.
		stringstream myStream(idString);
		if (myStream >> id){
			roadNode = MAP->findRoadNodeID(id);
			if(roadNode != NULL){
				break;
			}
		}
		cout << "Invalid ID, please try again" << endl;
	}

	if(action == ADD){
		if(MAP->centralNode == NULL){
			MAP->centralNode = roadNode;
		}
		roadNode->setCollectable();
	} else{
		if(MAP->centralNode == roadNode){
			MAP->centralNode = NULL;
		}
		roadNode->setUncollectable();
	}
}

void loadMap(){
	cout << "\n\nLoading map files...\n";
	parseFiles(MAP);
	cout << "\nEnd of file parsing. Press [enter] to return.\n";
	getchar();
}

void viewMap(){
	cout << "\n\nLoading Map...\n";
	if(JUNG_ON == 1){
		gv->closeWindow();
		JUNG_ON = 0;
		cout << "\nClosing Map. This may take a bit...\n\n";
	} else {
		if (JUNG_ON == 2)
			gv = new GraphViewer(600, 600, false);
		gv->createWindow(600, 600);
		Sleep(1000);
		parseGraph(MAP, gv);
		JUNG_ON = 1;
		cout << "\nLoading Map. This may take a bit...\n\n";
	}
	
	Sleep(1000);
}

void saveData(){
	if(circuits.size() > 0){
		cout << "\nType a name for the file that will contain the circuit information\n";
		cout << "Type 'exit' to return.\n";
		string fileName;
		cin >> fileName;
		if(!fileName.compare("exit"))
			return;
		saveToFile(fileName, &circuits);
	} else {
		cout << "\nThere is no circuit data to save.\n";
	}
}

void loadData(){
	cout << "\nType the name of the file that contains the circuit information\n";
	cout << "Type 'exit' to return.\n";
	string fileName;
	cin >> fileName;
	if(!fileName.compare("exit"))
		return;
	parseCircuitFile(fileName, &circuitIDs);
	for(int i = 0, s = circuitIDs.size(); i < s; i++){
		vector<RoadNode*> circuit;
		for(int j = 0, t = circuitIDs[i].size(); j < t; j++){
			circuit.push_back(MAP->findRoadNodeID(circuitIDs[i][j]));
		}
		circuits.push_back(circuit);
		circuit.clear();
	}
	// TODO MAP->setCircuits(circuits);

	MAP->getCircuits(1, &circuits);
	if(JUNG_ON != 1)
		viewMap();
	parseCircuitGraph(&circuits[0], gv);
}

void loadCollectables(){
	int stat;
	do {
		cout << "\nType the name of the file that contains information about collectables.\n";
		cout << "Type 'exit' to return.\n";
		string fileName;
		cin >> fileName;
		if(!fileName.compare("exit"))
			return;
		stat = parseCollectablesFile(fileName, MAP);
	} while (stat);
}

void saveCollectables(){
	int stat;
	do {
		cout << "\nType a name for the file where to save the information about collectables.\n";
		cout << "Type 'exit' to return.\n";
		string fileName;
		cin >> fileName;
		if(!fileName.compare("exit"))
			return;
		stat = saveCollectablesFile(fileName, MAP);
	} while (stat);
}

void defineCircuit(){
	/*cout << "\n\nStarting circuit algorithms.\n";
	vector<RoadNode*> collectables;
	MAP->getcollectables(&collectables);
	int s = collectables.size();
	circuits.clear();*/
	
	// From: http://www.codeproject.com/KB/cpp/arrayDinamic.aspx
	// Defining an two-dimensional array
	/*double ** matrix = 0;
	newSquareMatrix(s, &matrix);

	MAP->getAdjacencyMatrix(matrix, collectables);*/

	/*MAP->getCircuits(1, &circuits);
	if(JUNG_ON != 1)
		viewMap();
	parseCircuitGraph(&circuits[0], gv);
	cout << "\nEnd of circuit definition\n";
	cout << "\nPress [enter] to return\n";
	getchar();*/
	circuits.clear();
	vector<RoadNode*> promissing;
	vector<RoadNode*> collectables;

	RoadNode * firstNode = MAP->centralNode;
	//Search all collectables, excludes "central node".
	for(int i = 0, s = MAP->getRoadNodes().size(); i < s; i++){
		if(MAP->getRoadNodes()[i]->isCollectable() && MAP->getRoadNodes()[i] != MAP->centralNode){
			collectables.push_back(MAP->getRoadNodes()[i]);
		}
	}

	if(collectables.size() < 2){
		cerr << "\nConsider adding some collectables first.\nNo circuit defined\n";
		return;
	}

	//cout << collectables.size() << " collectable nodes loaded." << endl;

	MAP->getOptimal(firstNode, collectables, 0, promissing);
	circuits.push_back(potenciallyOptimal);
	if(JUNG_ON != 1)
		viewMap();
	parseCircuitGraph(&potenciallyOptimal, gv);
	getchar();
}

void testRoutine(){
	cout << "\n\nLoading map files...\n";
	parseFiles(MAP);
	parseCollectablesFile("collectables.txt", MAP);
	cout << "\nEnd of file parsing.\n";
	vector<RoadNode*> promissing;
	vector<RoadNode*> collectables;

	RoadNode * firstNode = MAP->centralNode;
	for(int i = 0, s = MAP->getRoadNodes().size(); i < s; i++){
		if(MAP->getRoadNodes()[i]->isCollectable() && MAP->getRoadNodes()[i] != MAP->centralNode){
			collectables.push_back(MAP->getRoadNodes()[i]);
		}
	}
	cout << collectables.size() << " collectable nodes loaded." << endl;

	MAP->getOptimal(firstNode, collectables, 0, promissing);
	circuits.push_back(potenciallyOptimal);
	if(JUNG_ON != 1)
		viewMap();
	parseCircuitGraph(&potenciallyOptimal, gv);
	getchar();
}

void main_menu(RoadMap * roadMap){
	MAP = roadMap;
	bool exit = false;
	while(!exit){	
		string message = "MAIN MENU :: What do you wish to do?\n";
		string options[MMENU_SIZE] = {"Add Collectable", "Remove Collectable", "Load Map", "View/Hide Map", "Define circuit", "Save circuit", "Load circuit", "Load Collectables", "Save Collectables"}; //, "Test"};
		switch (putMenu(message, options, MMENU_SIZE)) {
		case 0 :
			exit = true;
			break;
		case 1 :
			editCollectable(ADD);
			break;
		case 2 :
			editCollectable(REMOVE);
			break;
		case 3 :
			loadMap();
			break;
		case 4 :
			viewMap();
			break;
		case 5 :
			defineCircuit();
			break;
		case 6 :
			saveData();
			break;
		case 7 :
			loadData();
			break;
		case 8 :
			loadCollectables();
			break;
		case 9 :
			saveCollectables();
		case 10 :
			testRoutine();
		default :
			break;
		}
	}
	return;
}